package Day_0215.JVM;

/**
 * @author zxc
 * @date 2023/02/15 21:03
 **/
public class Object_Build {
    public static void main(String[] args) {
        /**
         * JVM虚拟机中对象创建的详细过程
         * ===》
         * 1.Java 中提供的几种对象创建方式：
         * （1）使用new关键字---调用了构造函数;
         * （2）使用Class的newInstance方法---调用了构造函数;
         * （3）使用Constructor类的newInstance方法---调用了构造函数;
         * （4）使用clone方法---没有调用构造函数;
         * （5）使用反序列化---没有调用构造函数;
         *
         * 2.创建对象的详细流程
         * （1）虚拟机遇到一条new指令时，先检查运行时常量池是否已经加载相应的类，如果没有，必须先执行相应的类加载。
         * （2）将类加载到运行时常量池后，为新创建的对象去分配内存 ：
         *  a.若Java堆中内存是绝对规整的，使用“指针碰撞“方式分配内存；
         *  b.如果不是规整的，就从空闲列表中分配，叫做”空闲列表“方式。
         * （3）划分内存时还需要考虑一个问题-并发，也有两种方式:
         *  CAS同步处理，或者本地线程分配缓冲(Thread Local Allocation Buffer, TLAB)。
         * （4）然后内存空间初始化操作，接着是做一些必要的对象设置(元信息、哈希码…)，
         * （5）最后执行 <init> 方法。
         *
         */

        /**
         * 创建对象流程中，为对象分配内存的详细理解
         * ===》
         * 1.类加载完成后，会在Java堆中划分一块内存分配给对象。
         * 内存分配根据Java堆是否规整，有两种方式：
         * （1）指针碰撞：
         *  如果Java堆的内存是规整，即所有用过的内存放在一边，而空闲的的放在另一边。
         *  分配内存时将位于中间的指针指示器向空闲的内存移动一段与对象大小相等的距离，这样便完成分配内存工作。
         * （2）空闲列表：
         *  如果Java堆的内存不是规整的，则需要由虚拟机维护一个列表来记录那些内存是可用的，
         *  这样，在分配的时候可以从列表中查询到足够大的内存分配给对象，并在分配后更新列表记录。
         *
         * 2.总结 ：
         * （1）对象内存分配方式，是由 Java 堆是否规整来决定的，
         * （2）Java 堆是否规整，又由所采用的垃圾收集器是否带有压缩整理功能决定。
         *
         */

        /**
         * 给对象分配内存的时候，需要考虑到并发问题
         * ===》
         * 1.高并发情况下，对象创建所带来的问题
         * 对象的创建，在虚拟机中是一个非常频繁的行为，哪怕只是修改一个指针所指向的位置，在并发情况下也是不安全的;
         * 可能出现正在给对象 A 分配内存，指针还没来得及修改，对象 B 又同时使用了原来的指针来分配内存的情况。
         *
         * 2.解决这个问题有两种方案：
         * （1）CAS同步处理 ：
         *  对给对象分配内存空间的动作,进行同步处理;
         *  （采用 CAS + 失败重试,来保障更新操作的原子性）;
         *
         * （2）TlAB(Thread Local ALLocation Buffer)本地线程缓冲 ：
         *  把内存分配的动作，按照线程划分在不同的空间之中进行，
         *  即，每个线程在 Java 堆中预先分配一小块内存，称为本地线程分配缓冲（Thread Local Allocation Buffer, TLAB）。
         *  哪个线程要分配内存，就在哪个线程的 TLAB 上分配。只有 TLAB 用完并分配新的 TLAB 时，才需要同步锁。
         *  通过-XX:+/-UserTLAB参数来设定虚拟机是否使用TLAB。
         *
         */
    }
}
